package org.liushengpei.com.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.liushengpei.com.constant.ResultMsgConstant;
import org.liushengpei.com.domain.User;
import org.liushengpei.com.domain.vo.RemoveUserVO;
import org.liushengpei.com.domain.vo.UserVO;
import org.liushengpei.com.mapper.SysUserMapper;
import org.liushengpei.com.service.IUserService;
import org.liushengpei.com.util.EncryptionUtil;
import org.liushengpei.com.util.MinioUtils;
import org.liushengpei.com.util.OnlyId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import static org.liushengpei.com.constant.RedisConstant.*;
import static org.liushengpei.com.constant.RegularConstant.EMAIL_CHECK;
import static org.liushengpei.com.constant.RegularConstant.PHONE_CHECK;

/**
 * 用户逻辑实现
 */
@Service
public class UserServiceImpl extends ServiceImpl<SysUserMapper, User> implements IUserService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private MinioUtils minioUtils;

    /**
     * 存储用户头像桶的名称
     */
    private static final String HEAD_IMAGE_BUCKET = "headimg";

    /**
     * 用户注册
     */
    @Override
    public String registerUser(String account, String onePwd, String twoPwd) {
        //数据校验
        if (account == null || account.equals("")) {
            return "账号不能为空";
        }
        if (onePwd == null || onePwd.equals("")) {
            return "密码不能为空";
        }
        if (twoPwd == null || twoPwd.equals("")) {
            return "密码不能为空";
        }
        //判断两次密码是否一致
        if (!onePwd.equals(twoPwd)) {
            return "两次密码不一致，请重新输入密码";
        }
        //判断此账号数据库是否存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getAccount, account)
                .eq(User::getDelFlag, 0);
        User isExist = this.getOne(wrapper);
        //存在
        if (isExist != null) {
            return "该账号已注册";
        }
        //密码加密
        String md5Pwd = EncryptionUtil.md5(twoPwd);
        //不存在添加用户数据到数据库
        Long userId = OnlyId.nextId();
        User user = new User();
        user.setId(userId.toString());
        user.setAccount(account);
        user.setPassword(md5Pwd);
        user.setNickName("QT_" + account);
        user.setCreateTime(new Date());
        user.setStatus(0);
        user.setLoginNum(0);
        user.setDelFlag(0);
        user.setIdentifying(1); //用户
        boolean save = this.save(user);
        if (save) {
            return ResultMsgConstant.OK;
        }
        return ResultMsgConstant.FAIL;
    }

    /**
     * 用户登录
     */
    @Override
    public UserVO userLogin(String account, String password) {
        UserVO userVO = null;
        //密码加密后
        String md5Pwd = EncryptionUtil.md5(password);
        //查询数据库
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getAccount, account)
                .eq(User::getPassword, md5Pwd)
                .eq(User::getDelFlag, 0)
                .eq(User::getIdentifying, 1)
                .ne(User::getStatus, 2);
        User user = this.getOne(wrapper);
        //判断用户是否存在
        if (user != null) {
            //存储用户在redis,30分钟过期
            redisTemplate.opsForValue().set(USER_LOGIN + user.getId(), JSONObject.toJSONString(user), USER_EXPIRE_TIME, TimeUnit.MINUTES);
            //判断该用户token是否存在
            String oldToken = redisTemplate.opsForValue().get(LOGIN_TOKEN + user.getId());
            if (!"".equals(oldToken)) {
                //删除该用户旧的token
                redisTemplate.delete(LOGIN_TOKEN + user.getId());
            }
            //创建新token
            Map<String, Object> map = new HashMap<>();
            map.put(TOKEN_USER_INFO, user.getId());
            map.put("dateTime", new Date());
            String token = JWTUtil.createToken(map, account.getBytes());
            //存储在redis,30天过期
            redisTemplate.opsForValue().set(LOGIN_TOKEN + user.getId(), token, TOKEN_EXPIRE_TIME, TimeUnit.DAYS);
            //更新登录状态为已登录
            LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(User::getAccount, account)
                    .set(User::getStatus, 1)
                    .set(User::getLoginTime, new Date())
                    .setSql("login_num=login_num+1");
            this.update(updateWrapper);
            //添加返回数据
            RemoveUserVO removeUserVO = new RemoveUserVO(user);
            userVO = new UserVO();
            userVO.setUserVO(removeUserVO);
            userVO.setToken(token);
        } else {
            return null;
        }
        return userVO;
    }

    /**
     * 用户修改密码
     */
    @Override
    public String updatePassword(String id, String oldPwd, String newPwd) {
        //根据id查询用户旧密码
        User sysUser = this.getById(id);
        String oldPwdVal = EncryptionUtil.md5(oldPwd);
        if (!sysUser.getPassword().equals(oldPwdVal)) {
            return "原始密码错误";
        }
        //判断两次密码是否一致
        if (!oldPwd.equals(newPwd)) {
            return "两次密码不一致";
        }
        //密码加密修改
        User user = new User();
        user.setId(id);
        user.setPassword(EncryptionUtil.md5(newPwd));
        user.setUpdateTime(new Date());
        //根据id修改密码
        boolean status = this.updateById(user);
        if (!status) {
            return "修改失败";
        }
        return "修改成功";
    }

    /**
     * 上传用户头像到minio
     */
    @Override
    public String uploadUserHeadFile(MultipartFile file) {
        String fileUrl = "";
        //判断桶是否存在
        boolean bucketExists = minioUtils.bucketExists(HEAD_IMAGE_BUCKET);
        if (!bucketExists) {
            //创建桶
            minioUtils.createBucket(HEAD_IMAGE_BUCKET);
        }
        //上传头像，获取地址
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            String fileName = file.getOriginalFilename();
            assert fileName != null;
            fileUrl = minioUtils.uploadFileReturnUrl(HEAD_IMAGE_BUCKET, fileName, inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fileUrl;
    }

    /**
     * 补充个人信息
     */
    @Override
    public String addMineInfo(User user) {
        //校验手机号
        if (user.getPhone() != null && !user.getPhone().equals("")) {
            boolean phoneCheck = Pattern.matches(PHONE_CHECK, user.getPhone());
            if (!phoneCheck) {
                return "电话号码格式有误";
            }
        }
        //判断电话号码验证码
        if (user.getPhoneCode() != null && !user.getPhoneCode().equals("")) {
            String phoneCode = redisTemplate.opsForValue().get(USER_PHONE_CODE + user.getPhone());
            if (phoneCode == null || phoneCode.equals("")) {
                return "绑定失败";
            }
            //判断是否与缓存的是否相等
            if (!phoneCode.equals(user.getPhoneCode())) {
                return "验证码验证失败";
            }
        }
        //校验邮箱
        if (user.getEmail() != null && !user.getEmail().equals("")) {
            boolean emailCheck = Pattern.matches(EMAIL_CHECK, user.getEmail());
            if (!emailCheck) {
                return "电子邮箱格式有误";
            }
        }
        //邮箱与验证码校验
        if (user.getEmail() != null && !user.getEmail().equals("")) {
            String emailCode = redisTemplate.opsForValue().get(USER_EMAIL_CODE + user.getEmail());
            if (emailCode == null || emailCode.equals("")) {
                return "绑定失败";
            }
            //判断是否与缓存相等
            if (!emailCode.equals(user.getEmailCode())) {
                return "验证码验证失败";
            }
        }
        //设置跟新时间
        user.setUpdateTime(new Date());
        boolean isSuccess = this.updateById(user);
        if (!isSuccess) {
            return "修改失败";
        }
        return "修改成功";
    }

    /**
     * 获取用户详细信息
     */
    @Override
    public RemoveUserVO getUserDetail(String id) {
        User sysUser = this.getById(id);
        return new RemoveUserVO(sysUser);
    }

    /**
     * 获取手机验证码
     */
    @Override
    public String getPhoneCode(String phone) {
        //校验手机号码
        boolean isCheck = Pattern.matches(PHONE_CHECK, phone);
        if (isCheck) {
            //随机生模拟成六位验证码（此处可以调用发送手机验证码的第三方接口）
            String phoneCode = RandomUtil.randomNumbers(6);
            //存储到redis,设置有效期5分钟
            redisTemplate.opsForValue().set(USER_PHONE_CODE + phone, phoneCode, CODE_EXPIRE_TIME, TimeUnit.MINUTES);
            return phoneCode;
        }
        return "电话号码格式有误";
    }

    /**
     * 获取邮箱验证码
     */
    @Override
    public String getEmailCode(String email) {
        //校验邮箱
        boolean isCheck = Pattern.matches(EMAIL_CHECK, email);
        if (isCheck) {
            //随机生模拟成六位验证码（此处可以调用发送手机验证码的第三方接口）
            String emailCode = RandomUtil.randomNumbers(6);
            //存储到redis,设置有效期5分钟
            redisTemplate.opsForValue().set(USER_EMAIL_CODE + email, emailCode, CODE_EXPIRE_TIME, TimeUnit.MINUTES);
            return emailCode;
        }
        return "电子邮箱格式有误";
    }
}
